<?php
class Customer_Model_Booking
{	
	/**
	 * Cancel order
	 * @param unknown_type $code
	 */
	public function cancelOrder($code)
	{
		$orderModel = new Customer_Model_Orders();
		$orderID = $orderModel->getOrderIDByCode($code);
		try {
			return $orderModel->deleteOrder($orderID);
		} catch(Exception $e) {		
			throw $e;
		}		
	}
	
	/**
	 * Book some tickets. This method is used for user logged in.
	 * @param int $customerID
	 * @param int $tripID
	 * @param int $seatCountYouWant
	 * @param array $seats
	 * @param array $tempSeats
	 * @return string
	 */
	public function bookingForExistCustomer($customerID, $tripID, $seatCountYouWant, $seats, $tempSeats)
	{
		if($customerID == null) throw new Exception('Customer ID is null');
		$db = Zend_Db_Table::getDefaultAdapter();
		$db->beginTransaction();
		try {
			// first create new order
			$code = uniqid();
			$orderID = $this->_insertOrder($customerID, $tripID, $code);
									
			// second create tickets of the order
			$tickets = $this->_insertTickets($seatCountYouWant, 
											 $seats,
											 $orderID, 
											 $tempSeats, 
											 $tripID);			
			$db->commit();			
			return $code;
		} catch(Zend_Exception $e) {
			$db->rollback();	
			throw $e;
		}
	}
	
	/**
	 * Book some tickets. This method is used for user has not logged in. The order of operation is: create customer, create order and create tickets. 
	 * @param string $name
	 * @param string $email
	 * @param string $ssn
	 * @param string $mobile
	 * @param int $tripID
	 * @param int $seatCountYouWant
	 * @param array $seats
	 * @param array $tempSeats
	 * @return string
	 */
	public function booking($name, $email, $ssn, $mobile,
							  $tripID, $seatCountYouWant, $seats, $tempSeats)
	{		
		$db = Zend_Db_Table::getDefaultAdapter();
		$db->beginTransaction();
		try {
			// first create customer
			$customerID = $this->_insertCustomer($name, $email, $ssn, $mobile);
			
			// second create new order
			$code = uniqid();
			$orderID = $this->_insertOrder($customerID, $tripID, $code);
						
			// at last create tickets of the order
			$tickets = $this->_insertTickets($seatCountYouWant, 
											 $seats,
											 $orderID, 
											 $tempSeats, 
											 $tripID);											 
			$db->commit();			
			return $code;
		} catch(Zend_Exception $e) {			
			$db->rollback();
			throw $e;
		}	
	}
	
	/**
	 * Insert ticket (helper)
	 * @param int $seatCountYouWant
	 * @param array $seats
	 * @param int $orderID
	 * @param array $tempSeats
	 * @param int $tripID
	 * @return array
	 */
	private function _insertTickets($seatCountYouWant, $seats, $orderID, $tempSeats, $tripID)
	{	
		// $seats has form: Array([1] => 'no', [2] => 'yesOnNormal', [3] => 'yesOnTemp', ...)
		// $tempSeats has form: Array([0] => [1], ...) with 0 is index, 1 is seat number.

		// check if the seat count is enough to book
		$arrayCountValues = array_count_values($seats);		
		$freeSeatCount = (!array_key_exists('no', $arrayCountValues)) ? 0 : $arrayCountValues['no'];
		$selectedNormalSeatCount = (!array_key_exists('yesOnNormal', $arrayCountValues)) ? 0 : $arrayCountValues['yesOnNormal'];
		$selectedTempSeatCount = (!array_key_exists('yesOnTemp', $arrayCountValues)) ? 0 : $arrayCountValues['yesOnTemp'];
		$remainingSeatCount = $seatCountYouWant - $selectedNormalSeatCount - $selectedTempSeatCount;
		
		if( $remainingSeatCount > $freeSeatCount || $freeSeatCount == 0) {		
			throw new Exception('Not enough available seats');
		}
		
		// store the seat numbers you selected as fixed seats, unset them from $seats,
		//// we will actually insert them later
		$tickets = array();
		$fixedSelectedSeats = array();
		$ticketModel = new Customer_Model_Ticket();
		foreach($seats as $seatNumber => $isBooked) {			
			if($isBooked != 'no') {
				// store this for later insert
				$fixedSelectedSeats[] = $seatNumber;
				
				// remove this seat from seats array
				unset($seats[$seatNumber]);
			}
		}			
		
		// translate temp seats of others backward
		$i = 0; $tempSeatCount = count($tempSeats);
		foreach($seats as $seatNumber => $isBooked) {
			if($i == $tempSeatCount) break;
			if($isBooked == 'no') {
				$ticketID = $tempSeats[$i];
				$this->_updateTempSeat($ticketID, $seatNumber);
				
				// remove this seat from seats array
				unset($seats[$seatNumber]);
				++$i;
			}
		}		
		
		// create tickets you selected as fixed seats
		foreach($fixedSelectedSeats as $seatNumber) {
			$ticketID = $ticketModel->createTicket($orderID, $seatNumber, 1, $tripID);
			$tickets[] = $ticketID;
		}
			
		// create tickets you has not selected as temp seats
		$seatCountYouNotSelected = $remainingSeatCount;
		$i = 0;
		foreach($seats as $seatNumber => $isBooked) {			
			if($i == $seatCountYouNotSelected) break;
			if($isBooked == 'no') {
				$tickets[] = $ticketModel->createTicket($orderID, $seatNumber, 0, $tripID);
				
				// remove this seat from seats array
				unset($seats[$seatNumber]);
				++$i;
			}
		}
		
		return $tickets;
	}

	/**
	 * Insert order (helper)
	 * @param int $customerID
	 * @param array $tripID
	 * @param string $code
	 * @return array
	 */
	private function _insertOrder($customerID, $tripID, $code)
	{
		$ordersModel = new Customer_Model_Orders();
		$orderID = $ordersModel->createOrder($customerID, $tripID, $code);
		return $orderID;
	}
	
	/**
	 * Insert customer (helper)
	 * @param string $name
	 * @param string $email
	 * @param string $ssn
	 * @param string $mobile
	 * @return int
	 */
	private function _insertCustomer($name, $email, $ssn, $mobile)
	{
		$customerModel = new Customer_Model_Customer();
		return $customerModel->createCustomer($name, $email,
													 $ssn, $mobile);															
	}
	
	/**
	 * Update temporary seat (helper)
	 * @param unknown_type $ticketID
	 * @param unknown_type $seatNumber
	 * @return int
	 */
	private function _updateTempSeat($ticketID, $seatNumber)
	{
		$ticketModel = new Customer_Model_Ticket();
		$ticketModel->updateTempSeat($ticketID, $seatNumber);
	}
}